// This source code demonstrates how to connect to Access 2007
// .accdb database from C++ using the ODBC Data Access Technology.
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// This sample code is provided to illustrate a concept and 
// should not be used in applications or Web sites, as it 
// may not illustrate the safest coding practices. Microsoft 
// assumes no liability for incidental or consequential damages 
// should the sample code be used for purposes 
// other than as intended.

#include <afxdb.h>
#include <iostream>

using namespace std;

// Data Access Method used in this sample
const char* DAM = "MFC ODBC";

// Connection string for MFC ODBC 
LPCTSTR lpszConnect = 
    _T("Driver={Microsoft Access Driver (*.mdb, *.accdb)};DSN='';DBQ=C:\\Northwind 2007.accdb;");

int _tmain(int argc, _TCHAR* argv[])
{
    BOOL result = TRUE;
    CDatabase db;
    
    TRY
    {
        result = db.OpenEx(lpszConnect, 
            CDatabase::openReadOnly |
            CDatabase::noOdbcDialog);
        if (FALSE == result)
        {
            cout<<DAM<<": Unable to connect to data source "<<lpszConnect<<endl;
            return result;
        }

        cout<<DAM<<": Successfully connected to database. Data source name:\n  "
            <<db.GetDatabaseName()<<endl;

        // Prepare SQL query
        LPCTSTR query = "SELECT Customers.[Company], Customers.[First Name] FROM Customers;";
        cout<<DAM<<": SQL query:\n  "<<query<<endl;
           
        // Excecute the query and create a record set
        CRecordset rs(&db); 
        result = rs.Open(CRecordset::dynaset, query, CRecordset::none);
        if (result == TRUE)
        {
            cout<<DAM<<": Retrieve schema info for the given result set: "<<endl;
            CODBCFieldInfo fInfo; 
            short sFieldCount = rs.GetODBCFieldCount();
            if (sFieldCount > 0)
            {
                for (short nIndex=0; nIndex < sFieldCount; nIndex++)
                {
                    CODBCFieldInfo fInfo;
                    rs.GetODBCFieldInfo(nIndex, fInfo);
                    cout<<" | "<<fInfo.m_strName;
                }
                cout<<endl;
            }
            else
            {
                cout<<DAM<<": Error: Number of fields in the result set is 0."<<endl;
            }
        
            cout<<DAM<<": Fetch the actual data: "<<endl;
            CDBVariant var;
            CString value;
           
            // Loop through the rows in the result set
            int rowCount = 0;
            while (!rs.IsEOF())
            {
                for (short nIndex=0; nIndex < sFieldCount; nIndex++)
                {
                    rs.GetFieldValue(nIndex, var);
                    switch (var.m_dwType)
                    {
                        case DBVT_STRING:
                            value.Format("%s", var.m_pstring->GetBuffer(var.m_pstring->GetLength()));
                            break;
                        case DBVT_ASTRING:
                            value.Format("%s", var.m_pstringA->GetBuffer(var.m_pstringA->GetLength()));
                            break;
                        case DBVT_WSTRING:
                            value.Format("%s", var.m_pstringW->GetBuffer(var.m_pstringW->GetLength()));
                            break;
                        default:
                            value = "";
                    }
                    cout<<" | "<<value;
                }
                cout<<endl;
                rowCount++;
                rs.MoveNext();
            }
            cout<<DAM<<": Total Row Count: "<<rowCount<<endl;
        }
    }
    CATCH_ALL(e)
    {
        TCHAR  errMsg[255];
        e->GetErrorMessage(errMsg, 255);
        cout<<DAM<<": CException: "<<errMsg<<endl;
    }
    END_CATCH_ALL
   
    db.Close();
    cout<<DAM<<": Cleanup. Done."<<endl;

    return result;
}